// Copyright 2022 a.o.smith ALL Rights Reserved
package com.liuxinlong.modules.specialist.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.liuxinlong.common.AosException;
import com.liuxinlong.common.ExcelData;
import com.liuxinlong.common.SnowFlake;
import com.liuxinlong.constant.ThreadLocalConstants;
import com.liuxinlong.constant.TimeFormatConstants;
import com.liuxinlong.enums.DifficultyStatusEnum;
import com.liuxinlong.enums.ReturnCodes;
import com.liuxinlong.modules.dao.DifficultyDao;
import com.liuxinlong.modules.dao.DifficultyPlanDao;
import com.liuxinlong.modules.dao.ExpertDao;
import com.liuxinlong.modules.dao.ExpertProjectDao;
import com.liuxinlong.modules.dao.ProjectNewsDao;
import com.liuxinlong.modules.dao.RoleDao;
import com.liuxinlong.modules.dao.UserDao;
import com.liuxinlong.modules.dao.UserRoleRelationDao;
import com.liuxinlong.modules.entity.Difficulty;
import com.liuxinlong.modules.entity.DifficultyPlan;
import com.liuxinlong.modules.entity.Expert;
import com.liuxinlong.modules.entity.ExpertProject;
import com.liuxinlong.modules.entity.ProjectNews;
import com.liuxinlong.modules.entity.User;
import com.liuxinlong.modules.entity.UserRole;
import com.liuxinlong.modules.entity.UserRoleRelation;
import com.liuxinlong.modules.specialist.service.DifficultyService;
import com.liuxinlong.utils.ExcelUtils;
import com.liuxinlong.utils.ObjectUtils;
import com.liuxinlong.utils.ThreadlocalUtils;
import com.liuxinlong.utils.TimeUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;


/**
 * 技术难点信息服务层实现类
 *
 * @author liuxinlong@hotwater.com.cn
 * @version 1.0.0
 * @since 2023年3月22日
 */
@Slf4j
@Service
public class DifficultyServiceImpl implements DifficultyService {

    @Autowired
    private DifficultyDao difficultyDao;

    @Autowired
    private UserDao userDao;

    @Autowired
    private ExpertProjectDao projectDao;

    @Autowired
    private ExpertDao expertDao;

    @Autowired
    private DifficultyPlanDao difficultyPlanDao;

    @Autowired
    private ProjectNewsDao projectNewsDao;

    @Autowired
    private RoleDao roleDao;

    @Autowired
    private UserRoleRelationDao userRoleRelationDao;

    @Override
    public List<Map<String, Object>> pageDifficultyInfo(Map<String, Object> queryParam) {
        int startNum = (int) queryParam.get("startNum");
        List<Difficulty> originList = difficultyDao.pageDifficultyList(queryParam);
        return completeResult(originList, startNum);
    }

    @Override
    public int getDifficultyCount(Map<String, Object> queryParam) {
        return difficultyDao.getDifficultyCount(queryParam);
    }

    @Override
    @Transactional
    public void addDifficultyInfo(Difficulty difficulty) {
        ExpertProject projectInfo = projectDao.selectById(difficulty.getProjectId());
        if (ObjectUtils.isEmpty(projectInfo)) {
            throw new AosException(ReturnCodes.HTTP_PARAM_ERROR, "新增失败，项目不存在！");
        }
        User currentUser = (User) ThreadlocalUtils.getCache(ThreadLocalConstants.USER_INFO);
        if (ObjectUtils.isEmpty(currentUser)) {
            throw new AosException(ReturnCodes.HTTP_PARAM_ERROR, "用户登陆状态异常！");
        }
        difficulty.setId(SnowFlake.nextIdStr());
        difficulty.setStatus(DifficultyStatusEnum.ONGOING.getValue());
        difficulty.setCreateUser(currentUser.getId());
        difficulty.setExpiryDate(difficulty.getExpiryDate().substring(0, 10));
        String currentTime = TimeUtils.getDate(TimeFormatConstants.YYYY_MM_DD_HH_MM_SS);
        difficulty.setCreateTime(currentTime);
        difficultyDao.insert(difficulty);
        if (difficulty.getPointType() == 2) {
            String experts = difficulty.getAssistExpert();
            if (StringUtils.isEmpty(experts)) {
                return;
            }
            expertDao.updateRiskCount(Arrays.asList(experts.split(",")));
        } else {
            if (StringUtils.isEmpty(difficulty.getAssistExpert())) {
                return;
            }
            List<String> expertList = Arrays.asList(difficulty.getAssistExpert().split(","));
        }
    }

    @Override
    @Transactional
    public void updateDifficultyInfo(Difficulty difficulty) {
        User currentUser = (User) ThreadlocalUtils.getCache(ThreadLocalConstants.USER_INFO);
        if (ObjectUtils.isEmpty(currentUser)) {
            throw new AosException(ReturnCodes.HTTP_PARAM_ERROR, "用户登陆状态异常！");
        }
        Difficulty oldInfo = difficultyDao.selectById(difficulty.getId());
        if (ObjectUtils.isEmpty(oldInfo)) {
            throw new AosException(ReturnCodes.HTTP_PARAM_ERROR, "修改失败，原技术难点信息不存在！");
        }
        ExpertProject project = projectDao.selectById(oldInfo.getProjectId());
        List<UserRoleRelation> userRoleRelationList = userRoleRelationDao.queryRelationByUserId(currentUser.getId());
        UserRole manageRole = roleDao.getRoleBySn("J017");
        List<UserRoleRelation> existList;
        if (ObjectUtils.isEmpty(manageRole)) {
            existList = new ArrayList<>();
        } else {
            existList = userRoleRelationList.stream().filter(relation -> StringUtils.equals(relation.getRoleId(), manageRole.getId())).collect(Collectors.toList());
        }
        if (!StringUtils.equals(currentUser.getId(), oldInfo.getLiableMember()) && !StringUtils.equals(currentUser.getId(), project.getProjectManager()) && existList.isEmpty()) {
            throw new AosException(ReturnCodes.HTTP_PARAM_ERROR, "当前用户没有权限修改！");
        }
        oldInfo.setFinishRate(difficulty.getFinishRate());
        String currentTime = TimeUtils.getDate(TimeFormatConstants.YYYY_MM_DD_HH_MM_SS);
        oldInfo.setStatus(TimeUtils.compareDate(currentTime.substring(0,10),difficulty.getExpiryDate(),TimeFormatConstants.YYYY_MM_DD) < 0 ? DifficultyStatusEnum.ONGOING.getValue() : oldInfo.getStatus());
        if (difficulty.getFinishRate() == 100) {
            oldInfo.setStatus(DifficultyStatusEnum.FINISHED.getValue());
            Set<String> expertSet = new HashSet<>();
            Map<String, Object> queryPlanParam = new HashMap<>();
            queryPlanParam.put("difficultyId", difficulty.getId());
            queryPlanParam.put("startNum", 0);
            queryPlanParam.put("pageSize", 10000);
            List<DifficultyPlan> planList = difficultyPlanDao.pageDifficultyPlanList(queryPlanParam);
            for (DifficultyPlan plan : planList) {
                if (plan.getFeedback() == 1 && plan.getStatus() != 1) {
                    expertSet.add(plan.getExpertId());
                }
            }
            if (!ObjectUtils.isEmpty(expertSet)) {
                expertDao.updateSolveCount(new ArrayList<>(expertSet));
            }
        }
        oldInfo.setAssistExpert(difficulty.getAssistExpert());
        oldInfo.setDifficultyName(difficulty.getDifficultyName());
        oldInfo.setExpiryDate(difficulty.getExpiryDate());
        oldInfo.setLiableMember(difficulty.getLiableMember());
        oldInfo.setRemark(difficulty.getRemark());
        difficulty.setUpdateTime(currentTime);
        difficultyDao.updateById(oldInfo);
    }

    @Override
    @Transactional
    public void deleteDifficultyInfo(String id) {
        User currentUser = (User) ThreadlocalUtils.getCache(ThreadLocalConstants.USER_INFO);
        if (ObjectUtils.isEmpty(currentUser)) {
            throw new AosException(ReturnCodes.HTTP_PARAM_ERROR, "用户登陆状态异常！");
        }
        Difficulty difficulty = difficultyDao.selectById(id);
        List<UserRoleRelation> userRoleRelationList = userRoleRelationDao.queryRelationByUserId(currentUser.getId());
        UserRole manageRole = roleDao.getRoleBySn("J017");
        List<UserRoleRelation> existList;
        if (ObjectUtils.isEmpty(manageRole)) {
            existList = new ArrayList<>();
        } else {
            existList = userRoleRelationList.stream().filter(relation -> StringUtils.equals(relation.getRoleId(), manageRole.getId())).collect(Collectors.toList());
        }
        if (!StringUtils.equals(currentUser.getId(), difficulty.getCreateUser()) && existList.isEmpty()) {
            throw new AosException(ReturnCodes.HTTP_PARAM_ERROR, "当前用户没有权限修改！");
        }
        difficulty.setStatus(DifficultyStatusEnum.REPEALED.getValue());
        difficulty.setUpdateUser(currentUser.getId());
        String currentTime = TimeUtils.getDate(TimeFormatConstants.YYYY_MM_DD_HH_MM_SS);
        difficulty.setUpdateTime(currentTime);
        difficultyDao.updateById(difficulty);
        if (difficulty.getPointType() == 1) {
            Set<String> expertSet = new HashSet<>();
            Map<String, Object> queryPlanParam = new HashMap<>();
            queryPlanParam.put("difficultyId", id);
            queryPlanParam.put("startNum", 0);
            queryPlanParam.put("pageSize", 10000);
            List<DifficultyPlan> planList = difficultyPlanDao.pageDifficultyPlanList(queryPlanParam);
            List<DifficultyPlan> newPlanList = new ArrayList<>(planList.size());
            for (DifficultyPlan plan : planList) {
                if (plan.getFeedback() == 1) {
                    expertSet.add(plan.getExpertId());
                }
                plan.setStatus(1);
                plan.setUpdateUser(currentUser.getId());
                plan.setUpdateTime(currentTime);
                newPlanList.add(plan);
            }
            if (ObjectUtils.isEmpty(expertSet))
                return;
            difficultyPlanDao.updateBatchById(newPlanList);
            expertDao.reduceSolveCount(new ArrayList<>(expertSet));
            return;
        }
        List<String> expertList = Arrays.asList(difficulty.getAssistExpert().split(","));
        expertDao.reduceRiskCount(expertList);
    }

    @Override
    public void exportDifficultyInfo(String projectId, int pointType, HttpServletResponse response) {
        Map<String, Map<String, String>> userMap = userDao.getUserMap();
        ExpertProject project = projectDao.selectById(projectId);
        if (ObjectUtils.isEmpty(project)) {
            throw new AosException(ReturnCodes.HTTP_PARAM_ERROR, "项目不存在！");
        }
        ExcelData data = new ExcelData();
        data.setFileName("技术难点清单导出excel.xlsx");
        Map<String, Object> queryParam = new HashMap<>();
        queryParam.put("projectId", projectId);
        queryParam.put("pointType", pointType);
        queryParam.put("startNum", 0);
        queryParam.put("pageSize", 1000);
        List<Difficulty> questionList = difficultyDao.pageDifficultyList(queryParam);
        if (pointType == 1) {
            String[] head = {"序号", "项目名称", "技术难点", "状态", "责任人", "协助专家", "难点描述", "截止日期", "完成情况"};
            data.setHead(head);
            String[][] dataList = new String[questionList.size()][head.length];
            int index = 0;
            for (Difficulty item : questionList) {
                dataList[index][0] = String.valueOf(index + 1);
                dataList[index][1] = project.getProjectName();
                dataList[index][2] = item.getDifficultyName();
                dataList[index][3] = DifficultyStatusEnum.getNameByValue(item.getStatus());
                dataList[index][4] = userMap.containsKey(item.getLiableMember()) ? userMap.get(item.getLiableMember()).get("name") : item.getLiableMember();
                if (!StringUtils.isEmpty(item.getAssistExpert())) {
                    List<String> expertList = Arrays.asList(item.getAssistExpert().split(","));
                    List<String> expertNameList = new ArrayList<>();
                    for (String expertId : expertList) {
                        if (!userMap.containsKey(expertId)) {
                            continue;
                        }
                        expertNameList.add(userMap.get(expertId).get("name"));
                    }
                    dataList[index][5] = StringUtils.strip(expertNameList.toString(), "[]");
                } else {
                    dataList[index][5] = "";
                }
                dataList[index][6] = item.getRemark();
                dataList[index][7] = item.getExpiryDate();
                dataList[index][8] = item.getFinishRate() + "%";
                index++;
            }
            data.setData(Arrays.asList(dataList));
        } else if (pointType == 2) {
            String[] head = {"序号", "项目名称", "风险点", "提出专家", "风险点描述", "截止日期","状态" };
            data.setHead(head);
            String[][] dataList = new String[questionList.size()][head.length];
            int index = 0;
            for (Difficulty item : questionList) {
                dataList[index][0] = String.valueOf(index + 1);
                dataList[index][1] = project.getProjectName();
                dataList[index][2] = item.getDifficultyName();
                if (!StringUtils.isEmpty(item.getAssistExpert())) {
                    List<String> expertList = Arrays.asList(item.getAssistExpert().split(","));
                    List<String> expertNameList = new ArrayList<>();
                    for (String expertId : expertList) {
                        if (!userMap.containsKey(expertId)) {
                            continue;
                        }
                        expertNameList.add(userMap.get(expertId).get("name"));
                    }
                    dataList[index][3] = StringUtils.strip(expertNameList.toString(), "[]");
                } else {
                    dataList[index][3] = "";
                }
                dataList[index][4] = item.getRemark();
                dataList[index][5] = item.getExpiryDate();
                dataList[index][6] = item.getStatus() == 4 ? "无效" : "有效";
                index++;
            }
            data.setData(Arrays.asList(dataList));
        }
        ExcelUtils.exportExcel(response, data);
    }

    @Override
    public List<Map<String, Object>> pageDifficultyPlanInfo(Map<String, Object> queryParam) {
        boolean single = queryParam.containsKey("difficultyId");
        Difficulty difficultyInfo = new Difficulty();
        Map<String, Map<String, String>> difficultyMap = new HashMap<>();
        if (single) {
            difficultyInfo = difficultyDao.selectById((String) queryParam.get("difficultyId"));
        } else {
            difficultyMap = difficultyDao.getDifficultyMap((String) queryParam.get("projectId"));
        }

        List<DifficultyPlan> difficultyPlanList = difficultyPlanDao.pageDifficultyPlanList(queryParam);
        List<Map<String, Object>> dataList = new ArrayList<>(difficultyPlanList.size());
        Map<String, Map<String, String>> userMap = userDao.getUserMap();
        int sort = (int) queryParam.get("startNum") + 1;
        for (DifficultyPlan difficultyPlan : difficultyPlanList) {
            Map<String, Object> item = ObjectUtils.object2Map(difficultyPlan);
            item.put("sort", sort);
            item.put("expertName", userMap.containsKey(difficultyPlan.getExpertId()) ? userMap.get(difficultyPlan.getExpertId()).get("name") : "");
            item.put("difficultyName", single ? difficultyInfo.getRemark() : difficultyMap.containsKey(difficultyPlan.getDifficultyId()) ? difficultyMap.get(difficultyPlan.getDifficultyId()).get("remark") : "");
            item.put("feedbackInfo", difficultyPlan.getFeedback() == 1 ? "有效" : difficultyPlan.getFeedback() == 2 ? "无效" : "未反馈");
            dataList.add(item);
            sort++;
        }
        return dataList;
    }

    @Override
    public int getDifficultyPlanCount(Map<String, Object> queryParam) {
        return difficultyPlanDao.getDifficultyPlanCount(queryParam);
    }

    @Override
    @Transactional
    public void addDifficultyPlanInfo(DifficultyPlan difficultyPlan) {
        String difficultyId = difficultyPlan.getDifficultyId();
        if (StringUtils.isEmpty(difficultyId)) {
            throw new AosException(ReturnCodes.HTTP_PARAM_ERROR, "技术难点不存在！");
        }
        Difficulty difficulty = difficultyDao.selectById(difficultyId);
        if (ObjectUtils.isEmpty(difficulty)) {
            throw new AosException(ReturnCodes.HTTP_PARAM_ERROR, "技术难点不存在！");
        }
        ExpertProject project = projectDao.selectById(difficulty.getProjectId());
        if (ObjectUtils.isEmpty(project)) {
            throw new AosException(ReturnCodes.HTTP_PARAM_ERROR, "项目不存在！");
        }
        difficultyPlan.setId(SnowFlake.nextIdStr());
        User current = (User) ThreadlocalUtils.getCache(ThreadLocalConstants.USER_INFO);
        difficultyPlan.setCreateUser(current.getId());
        String createTime = TimeUtils.getDate(TimeFormatConstants.YYYY_MM_DD_HH_MM_SS);
        difficultyPlan.setCreateTime(createTime);
        difficultyPlanDao.insert(difficultyPlan);
        ProjectNews projectNews = new ProjectNews();
        projectNews.setId(SnowFlake.nextIdStr());
        projectNews.setCreateUser(current.getId());
        projectNews.setCreateTime(createTime);
        if (StringUtils.isEmpty(difficultyPlan.getExpertId())) {
            throw new AosException(ReturnCodes.HTTP_PARAM_ERROR, "未选择专家！");
        }
        Expert expertInfo = expertDao.selectById(difficultyPlan.getExpertId());
        if (ObjectUtils.isEmpty(expertInfo)) {
            throw new AosException(ReturnCodes.HTTP_PARAM_ERROR, "专家不存在！");
        }
        projectNews.setContent("专家 " + expertInfo.getName() + " 更新了【" + project.getProjectName() + "】项目技术难点的解决方案");
        projectNewsDao.insert(projectNews);
//        List<String> expertList = new ArrayList<>();
//        expertList.add(difficultyPlan.getExpertId());
//        expertDao.updateSolveCount(expertList);
    }

    @Override
    public void updateDifficultyPlanInfo(DifficultyPlan difficultyPlan) {
        Difficulty difficulty = difficultyDao.selectById(difficultyPlan.getDifficultyId());
        if (ObjectUtils.isEmpty(difficulty)) {
            throw new AosException(ReturnCodes.HTTP_PARAM_ERROR, "技术难点不存在！");
        }
        String currentTime = TimeUtils.getDate(TimeFormatConstants.YYYY_MM_DD_HH_MM_SS);
        difficultyPlan.setUpdateTime(currentTime);
        User current = (User) ThreadlocalUtils.getCache(ThreadLocalConstants.USER_INFO);
        difficultyPlan.setUpdateUser(current.getId());
        difficultyPlanDao.updateById(difficultyPlan);
    }

    @Override
    public void deleteDifficultyPlanInfo(String id) {
        DifficultyPlan difficultyPlan = difficultyPlanDao.selectById(id);
        if (ObjectUtils.isEmpty(difficultyPlan)) {
            throw new AosException(ReturnCodes.HTTP_PARAM_ERROR, "专家建议不存在！");
        }
        User currentUser = (User) ThreadlocalUtils.getCache(ThreadLocalConstants.USER_INFO);
        difficultyPlan.setStatus(1);
        difficultyPlan.setUpdateUser(currentUser.getId());
        String currentTime = TimeUtils.getDate(TimeFormatConstants.YYYY_MM_DD_HH_MM_SS);
        difficultyPlan.setUpdateTime(currentTime);
        difficultyPlanDao.updateById(difficultyPlan);
    }

    @Override
    public void exportDifficultyPlanInfo(String id, HttpServletResponse response) {
        Map<String, Map<String, String>> userMap = userDao.getUserMap();
        Difficulty difficulty = difficultyDao.selectById(id);
        if (ObjectUtils.isEmpty(difficulty)) {
            throw new AosException(ReturnCodes.HTTP_PARAM_ERROR, "技术难点不存在！");
        }
        ExcelData data = new ExcelData();
        data.setFileName("专家方案清单导出excel.xlsx");
        Map<String, Object> queryParam = new HashMap<>();
        queryParam.put("difficultyId", id);
        queryParam.put("startNum", 0);
        queryParam.put("pageSize", 1000);
        List<DifficultyPlan> planList = difficultyPlanDao.pageDifficultyPlanList(queryParam);
        String[] head = {"序号", "技术难点", "提出专家", "提出日期", "方案内容", "方案反馈"};
        data.setHead(head);
        String[][] dataList = new String[planList.size()][head.length];
        int index = 0;
        for (DifficultyPlan item : planList) {
            dataList[index][0] = String.valueOf(index + 1);
            dataList[index][1] = difficulty.getRemark();
            dataList[index][2] = userMap.containsKey(item.getExpertId()) ? (userMap.get(item.getExpertId())).get("name") : item.getExpertId();
            dataList[index][3] = item.getSuggestTime();
            dataList[index][4] = item.getContent();
            dataList[index][5] = item.getFeedback() == 1 ? "有效" : item.getFeedback() == 2 ? "无效" : "未反馈";
            index++;
        }
        data.setData(Arrays.asList(dataList));
        ExcelUtils.exportExcel(response, data);
    }

    @Override
    public void feedbackDifficultyPlanInfo(String id, int feedback) {
        DifficultyPlan difficultyPlan = difficultyPlanDao.selectById(id);
        if (ObjectUtils.isEmpty(difficultyPlan)) {
            throw new AosException(ReturnCodes.HTTP_PARAM_ERROR,"反馈失败，专家建议不存在！");
        }
        if (difficultyPlan.getFeedback() != 0) {
            throw new AosException(ReturnCodes.HTTP_PARAM_ERROR,"反馈失败，专家建议已反馈！");
        }
        difficultyPlan.setFeedback(feedback);
        String currentTime = TimeUtils.getDate(TimeFormatConstants.YYYY_MM_DD_HH_MM_SS);
        difficultyPlan.setUpdateTime(currentTime);
        User current = (User) ThreadlocalUtils.getCache(ThreadLocalConstants.USER_INFO);
        difficultyPlan.setUpdateUser(current.getId());
        difficultyPlanDao.updateById(difficultyPlan);
    }

    /**
     * 补全数据
     *
     * @param originList 原始数据
     * @param startNum   起始数
     * @return 补全数据列表
     */
    private List<Map<String, Object>> completeResult(List<Difficulty> originList, int startNum) {
        List<Map<String, Object>> resultList = new ArrayList<>();
        if (ObjectUtil.isEmpty(originList)) {
            return resultList;
        }
        Map<String, Map<String, String>> userMap = userDao.getUserMap();
        Map<String, Map<String, String>> expertMap = expertDao.getExpertMap();
//        Map<String, Map<String, String>> projectMap = projectDao.getProjectMap();
        int sort = startNum + 1;
        for (Difficulty item : originList) {
            Map<String, Object> map = ObjectUtils.object2Map(item);
            map.put("sort", sort);
            map.put("statusName", DifficultyStatusEnum.getNameByValue(item.getStatus()));
            map.put("ownerName", userMap.containsKey(item.getLiableMember()) ? userMap.get(item.getLiableMember()).get("name") : "");
            List<String> expertList = Arrays.asList(item.getAssistExpert().split(","));
            List<String> expertNameList = new ArrayList<>();
            for (String expertId : expertList) {
                if (!expertMap.containsKey(expertId)) {
                    continue;
                }
                expertNameList.add(expertMap.get(expertId).get("name"));
            }
            map.put("expertList", StringUtils.strip(expertNameList.toString(), "[]"));
            //            map.put("projectManagerName",userMap.containsKey(item.getProjectManager()) ? userMap.get(item.getProjectManager()).get("name") : "");
//            map.put("projectLevelName", ProjectLevelEnum.getNameByValue(item.getProjectLevel()));
//            map.put("createUserName", userMap.get(item.getCreateUser()).get("name"));
//            map.put("expertList", completeExpertList(item, expertMap));
//            map.put("departmentName", departmentMap.containsKey(item.getDepartment()) ? departmentMap.get(item.getDepartment()).get("name") : "");
            resultList.add(map);
            sort++;
        }
        return resultList;
    }
}
